using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WebDAVSharp;
using OpenMetaverse;
using CableBeachMessages;

namespace InventoryServer
{
    public static class WebDAVHelper
    {
        /// <summary>
        /// Create WebDAV resource out of InventoryBase
        /// </summary>
        /// <param name="path">According to examples in RFC2518 this should be absolute path</param>
        /// <param name="invObject"></param>
        /// <returns></returns>
        public static IWebDAVResource InventoryToDAV(string path, InventoryBase invObject)
        {
            if (invObject is InventoryFolder)
            {
                InventoryFolder folder = (InventoryFolder)invObject;
                DateTime epoch = OpenMetaverse.Utils.Epoch;
                return new WebDAVFolder(path, epoch, epoch, DateTime.Now, false);
            }
            else if (invObject is InventoryItem)
            {
                InventoryItem item = (InventoryItem)invObject;
                DateTime creationDate = OpenMetaverse.Utils.UnixTimeToDateTime(item.CreationDate);
                return new WebDAVFile(path, CableBeachUtils.SLAssetTypeToContentType(item.AssetType), 0, creationDate, creationDate,
                    DateTime.Now, false, false);
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Updates inventory object with values from webdav resource
        /// </summary>
        /// <param name="invObject">The inventory object.</param>
        /// <param name="webdavResource">The webdav resource.</param>
        /// <returns>Inventory object with updated values</returns>
        public static InventoryBase DAVToInventory(InventoryBase invObject, IWebDAVResource webdavResource)
        {
            if (invObject is InventoryFolder)
            {
                InventoryFolder folder = (InventoryFolder)invObject;
                folder.Type = CableBeachUtils.ContentTypeToSLInvType(webdavResource.ContentType);
                //TODO: add other properties also somehow
                return folder;
            }
            else if (invObject is InventoryItem)
            {
                InventoryItem item = (InventoryItem)invObject;
                item.AssetType = CableBeachUtils.ContentTypeToSLAssetType(webdavResource.ContentType);
                item.InvType = CableBeachUtils.ContentTypeToSLInvType(webdavResource.ContentType);
                item.CreationDate = (int)OpenMetaverse.Utils.DateTimeToUnixTime(webdavResource.CreationDate);
                //TODO: add other properties also somehow
                return item;
            }
            else
            {
                return null;
            }
        }

        public static InventoryBase PathToInventory(string path, InventoryCollection collection)
        {
            // Traverse a path and return the corresponding inventory object
            if (path[path.Length - 1] != '/')
                path += "/";
            string[] pathElements = path.Split('/');
            InventoryFolder currentFolder;
            InventoryItem item = null;
            int newestItem = 0;

            if (collection.Folders.TryGetValue(collection.RootFolderID, out currentFolder))
            {
                for (int i = 1; i < pathElements.Length; i++)
                {
                    if (currentFolder.Children.Count == 0)
                    {
                        foreach (InventoryFolder iFold in collection.Folders.Values)
                        {
                            if (iFold.ParentID == currentFolder.ID)
                                currentFolder.Children.Add(iFold.ID, iFold);
                        }

                        foreach (InventoryItem iItem in collection.Items.Values)
                        {
                            if (iItem.ParentID == currentFolder.ID)
                                currentFolder.Children.Add(iItem.ID, iItem);
                        }
                    }

                    string element = pathElements[i];
                    if (element != String.Empty)
                    {
                        // Try to find the current element in the current folders children
                        foreach (InventoryBase child in currentFolder.Children.Values)
                        {
                            if (child is InventoryFolder)
                            {
                                InventoryFolder childFolder = (InventoryFolder)child;
                                if (childFolder.Name == element)
                                {
                                    currentFolder = childFolder;
                                    newestItem = i;
                                    break;
                                }
                            }
                            else if (child is InventoryItem)
                            {
                                InventoryItem childItem = (InventoryItem)child;
                                if (childItem.Name == element)
                                {
                                    item = childItem;
                                    newestItem = i;
                                    break;
                                }
                            }
                        }
                    }
                }

                // This is to ensure we are not returning root folder when item doesn't exist
                if (newestItem == pathElements.Length - 2 || path == "/")
                {
                    if (item != null)
                        return item;
                    else
                        return currentFolder;
                }
                else
                {
                    return null;
                }
            }

            return null;
        }

        public static InventoryBase PathToInventory(string path, InventoryFolder folder)
        {
            // Traverse a path and return the corresponding inventory object
            if (path[path.Length - 1] != '/')
                path += "/";
            string[] pathElements = path.Split('/');
            InventoryFolder currentFolder = folder;
            InventoryItem item = null;
            int newestItem = 0;

            for (int i = 0; i < pathElements.Length; i++)
            {
                string element = pathElements[i];
                if (element != String.Empty)
                {
                    // Try to find the current element in the current folders children
                    foreach (InventoryBase child in currentFolder.Children.Values)
                    {
                        if (child is InventoryFolder)
                        {
                            InventoryFolder childFolder = (InventoryFolder)child;
                            if (childFolder.Name == element)
                            {
                                currentFolder = childFolder;
                                newestItem = i;
                                break;
                            }
                        }
                        else if (child is InventoryItem)
                        {
                            InventoryItem childItem = (InventoryItem)child;
                            if (childItem.Name == element)
                            {
                                item = childItem;
                                newestItem = i;
                                break;
                            }
                        }
                    }
                }
            }

            // This is to ensure we are not returning root folder when item doesn't exist
            if (newestItem == pathElements.Length - 2 || path == "/")
            {
                if (item != null)
                    return item;
                else
                    return currentFolder;
            }
            else
            {
                return null;
            }
        }
    }
}
